import { DatabaseOperations, DatabaseOperationsFactory } from '../utils/database-operations.js';
import { BusinessException } from '../types/exceptions.js';
import { Pool as MySQLPool } from 'mysql2/promise';
import { Pool as PgPool } from 'pg';

/**
 * 关联服务基类
 * @description 提供通用的关联关系操作，减少重复代码
 */
export abstract class BaseRelationService<
  T extends Record<string, unknown>,
  CreateDto extends Record<string, unknown>,
  UpdateDto extends Record<string, unknown>,
  QueryDto extends Record<string, unknown>,
  Operations extends DatabaseOperations<T> & {
    getByFirstId?(firstId: number): Promise<T[]>;
    getBySecondId?(secondId: number): Promise<T[]>;
    deleteByFirstId?(firstId: number): Promise<boolean>;
    deleteBySecondId?(secondId: number): Promise<boolean>;
  },
> {
  protected dbOperations: Operations | null = null;

  constructor(
    private MySQLOperationsClass: new (pool: MySQLPool) => Operations,
    private PostgreSQLOperationsClass: new (pool: PgPool) => Operations
  ) {}

  /**
   * 获取数据库操作实例
   * @returns 数据库操作实例
   */
  protected getDbOperations(): Operations {
    if (!this.dbOperations) {
      this.dbOperations = DatabaseOperationsFactory.create<Operations>(
        this.MySQLOperationsClass,
        this.PostgreSQLOperationsClass
      );
    }
    return this.dbOperations;
  }

  /**
   * 创建关联记录
   * @param data 创建数据
   * @returns 创建的记录ID
   */
  async create(data: CreateDto): Promise<number> {
    return this.getDbOperations().create(data as Omit<T, 'id'>);
  }

  /**
   * 根据ID获取关联记录
   * @param id 记录ID
   * @returns 记录数据或null
   */
  async getById(id: number): Promise<T | null> {
    return this.getDbOperations().getById(id);
  }

  /**
   * 更新关联记录
   * @param id 记录ID
   * @param data 更新数据
   * @returns 是否更新成功
   */
  async update(id: number, data: UpdateDto): Promise<boolean> {
    const result = await this.getDbOperations().update(id, data as Partial<T>);
    if (!result) {
      throw new BusinessException('关联记录不存在或已被删除');
    }
    return result;
  }

  /**
   * 删除关联记录
   * @param id 记录ID
   * @returns 是否删除成功
   */
  async delete(id: number): Promise<boolean> {
    const result = await this.getDbOperations().delete(id);
    if (!result) {
      throw new BusinessException('关联记录不存在');
    }
    return result;
  }

  /**
   * 获取关联记录列表
   * @param page 页码，默认为1
   * @param pageSize 每页数量，默认为10
   * @param query 查询条件
   * @returns 分页的记录列表
   */
  async list(
    page: number = 1,
    pageSize: number = 10,
    query: QueryDto = {} as QueryDto
  ): Promise<{ total: number; list: T[]; page: number; pageSize: number }> {
    return this.getDbOperations().list(page, pageSize, query as Partial<T>);
  }

  /**
   * 根据第一个实体ID获取关联记录
   * @param firstId 第一个实体ID
   * @returns 关联记录列表
   */
  async getByFirstId(firstId: number): Promise<T[]> {
    const operations = this.getDbOperations();
    if (typeof operations.getByFirstId === 'function') {
      return operations.getByFirstId(firstId);
    }
    throw new Error('getByFirstId method not implemented');
  }

  /**
   * 根据第二个实体ID获取关联记录
   * @param secondId 第二个实体ID
   * @returns 关联记录列表
   */
  async getBySecondId(secondId: number): Promise<T[]> {
    const operations = this.getDbOperations();
    if (typeof operations.getBySecondId === 'function') {
      return operations.getBySecondId(secondId);
    }
    throw new Error('getBySecondId method not implemented');
  }

  /**
   * 删除第一个实体的所有关联记录
   * @param firstId 第一个实体ID
   * @returns 是否删除成功
   */
  async deleteByFirstId(firstId: number): Promise<boolean> {
    const operations = this.getDbOperations();
    if (typeof operations.deleteByFirstId === 'function') {
      return operations.deleteByFirstId(firstId);
    }
    throw new Error('deleteByFirstId method not implemented');
  }

  /**
   * 删除第二个实体的所有关联记录
   * @param secondId 第二个实体ID
   * @returns 是否删除成功
   */
  async deleteBySecondId(secondId: number): Promise<boolean> {
    const operations = this.getDbOperations();
    if (typeof operations.deleteBySecondId === 'function') {
      return operations.deleteBySecondId(secondId);
    }
    throw new Error('deleteBySecondId method not implemented');
  }

  /**
   * 验证关联记录是否存在
   * @param id 记录ID
   * @param errorMessage 错误消息
   * @returns 记录数据
   */
  protected async validateExists(id: number, errorMessage: string = '关联记录不存在'): Promise<T> {
    const record = await this.getById(id);
    if (!record) {
      throw new BusinessException(errorMessage);
    }
    return record;
  }
}
